package com.hvgroup.modules.sanic.service.manager;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.hvgroup.modules.sanic.domain.enums.ChartTypeEnum;
import org.apache.commons.lang3.ObjectUtils;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.*;
import java.util.regex.Pattern;

public class DbQaDataProcess {

    private static final Pattern CHINESE_PATTERN = Pattern.compile(".*[一-龥]+.*");
    private static final Pattern DATE_PATTERN = Pattern.compile("^\\d{4}-\\d{2}-\\d{2}$");
    private static final Pattern COUNT_PATTERN = Pattern.compile("\\* (100(\\.0)?)");

    private static boolean isNumber(String strNum) {
        if (strNum == null || strNum.trim().isEmpty()) return false;
        try {
            Double.parseDouble(strNum);
            return true;
        } catch (NumberFormatException e) {
            return false;
        }
    }

    private static boolean isNumeric(Object value) {
        try {
            Double.parseDouble(String.valueOf(value));
            return true;
        } catch (Exception e) {
            return false;
        }
    }

    private static boolean isValidDate(Object value) {
        return DATE_PATTERN.matcher(String.valueOf(value)).matches();
    }

    private static String formatValue(ChartTypeEnum typeEnum, JSONObject llmInfo, String key, Object value) {
        String strVal = String.valueOf(value);
        if (!isNumber(strVal)) return strVal == null || strVal.trim().isEmpty() ? "0" : strVal;

        BigDecimal decimal = new BigDecimal(strVal);
        if (key.contains("比例") || key.contains("占比") || key.contains("比率") ||
                key.contains("百分比") || key.contains("概率")) {

            String sql = llmInfo.getString("sql");
            if (sql != null && COUNT_PATTERN.matcher(sql).find()) {
                decimal = decimal.setScale(2, RoundingMode.HALF_UP);
            } else {
                decimal = decimal.multiply(new BigDecimal("100")).setScale(2, RoundingMode.HALF_UP);
            }
            return (typeEnum == ChartTypeEnum.TABLE_CHART || typeEnum == ChartTypeEnum.PIE_CHART)
                    ? decimal + "%" : decimal.toString();
        } else {
            return decimal.setScale(0, RoundingMode.HALF_UP).toString();
        }
    }

    private static List<Map<String, String>> processTableChart(JSONObject llmInfo, List<String> columnData, List<Map<String, Object>> chartData) {
        List<Map<String, String>> result = new ArrayList<>();
        for (Map<String, Object> data : chartData) {
            Map<String, String> row = new LinkedHashMap<>();
            for (String col : columnData) {
                row.put(col, formatValue(ChartTypeEnum.TABLE_CHART, llmInfo, col, data.getOrDefault(col, "")));
            }
            result.add(row);
        }
        return result;
    }

    private static List<Map<String, Object>> processPieChart(JSONObject llmInfo, List<String> columnData, List<Map<String, Object>> chartData) {
        List<Map<String, Object>> result = new ArrayList<>();
        for (Map<String, Object> row : chartData) {
            Map<String, Object> pieData = new HashMap<>();
            for (Map.Entry<String, Object> entry : row.entrySet()) {
                String key = entry.getKey();
                Object value = entry.getValue();
                if (key.equals(columnData.get(0))) {
                    pieData.put("name", value == null ? "" : value);
                } else {
                    String formatted = formatValue(ChartTypeEnum.PIE_CHART, llmInfo, key, value);
                    if (formatted.contains("%")) {
                        pieData.put("value", formatted.replace("%", ""));
                        pieData.put("percent", true);
                    } else {
                        pieData.put("value", formatted);
                        pieData.put("percent", false);
                    }
                }
            }
            result.add(pieData);
        }
        return result;
    }

    private static List<List<Object>> processBarChart(JSONObject llmInfo, List<String> columnData, List<Map<String, Object>> chartData) {
        List<List<Object>> result = new ArrayList<>();
        if (!chartData.isEmpty()) {
            List<String> columns = new ArrayList<>(columnData);
            columns.set(0, "product");

            for (int i = 1; i < columns.size(); i++) {
                String col = columns.get(i);
                if (col != null && !CHINESE_PATTERN.matcher(col).matches()) {
                    Map<String, Object> firstRow = chartData.get(0);
                    Object item = firstRow.get(col);
                    if (isNumeric(item)) {
                        columns.set(i, "数量");
                    } else if (isValidDate(item)) {
                        columns.set(i, "日期");
                    }
                }
            }
            result.add(new ArrayList<>(columns));

            for (Map<String, Object> row : chartData) {
                List<Object> rowData = new ArrayList<>();
                for (String col : columnData) {
                    Object value = row.getOrDefault(col, "");
                    if (!isNumeric(value)) {
                        rowData.add((value == null || value.toString().isEmpty()) ? "未知" : value);
                    } else {
                        rowData.add(formatValue(ChartTypeEnum.BAR_CHART, llmInfo, col, value));
                    }
                }
                result.add(rowData);
            }
        }
        return result;
    }

    private static List<List<Object>> processLineChart(JSONObject llmInfo, List<String> columnData, List<Map<String, Object>> chartData) {
        List<Object> dates = new ArrayList<>();
        List<Object> values = new ArrayList<>();

        for (Map<String, Object> row : chartData) {
            for (Map.Entry<String, Object> entry : row.entrySet()) {
                if (entry.getKey().equals(columnData.get(0))) {
                    dates.add(entry.getValue());
                } else {
                    values.add(formatValue(ChartTypeEnum.LINE_CHART, llmInfo, entry.getKey(), entry.getValue()));
                }
            }
        }

        List<List<Object>> result = new ArrayList<>();
        result.add(dates);
        result.add(values);
        return result;
    }


    public static String process(Map<String, Object> data) {
        Map<String, Object> defaultResult = new HashMap<>();
        defaultResult.put("chart_type", ChartTypeEnum.TABLE_CHART.getCode());
        defaultResult.put("template_code", ChartTypeEnum.TABLE_CHART.getTemplateCode());

        defaultResult.put("data", new ArrayList<>());
        defaultResult.put("note", "数据来源: xxx数据库，以上数据仅供参考，具体情况可能会根据xx进一步调查和统计而有所变化");

        if (ObjectUtils.isEmpty(data)) {
            return JSON.toJSONString(defaultResult);
        }

        JSONObject llm_info = (JSONObject) data.get("llm");
        String chart_type = (String) llm_info.get("type");
        ChartTypeEnum typeEnum = ChartTypeEnum.getEnumByCode(chart_type);

        Map<String, Object> data_obj = (Map<String, Object>) data.get("data");
        if (ObjectUtils.isEmpty(data_obj)) {
            return JSON.toJSONString(defaultResult);
        }


        List<Map<String, Object>> chart_data = (List<Map<String, Object>>) data_obj.get("result");
        List<String> columnData = (List<String>) data_obj.get("column");

        // 使用字典推导创建schema map schema_map = {item["column"]: item["comment"] for item in json_data.get("schema",
        // [{}])[0].get("schemaData", [])}

        Pattern chinesePattern = Pattern.compile("^[\u4e00-\u9fa5]+$");

        if (columnData.size() == 1) {
            typeEnum = ChartTypeEnum.TABLE_CHART;

        } else if (typeEnum == ChartTypeEnum.PIE_CHART && columnData.size() > 2) {
            typeEnum = ChartTypeEnum.TABLE_CHART;

        } else if (typeEnum == ChartTypeEnum.BAR_CHART) {
            // 如果大模型返回柱状图且如果包含多列中文，则使用表格展示
            if (ObjectUtils.isNotEmpty(chart_data)) {
                Map<String, Object> jsonObject = chart_data.get(0);
                if (ObjectUtils.isNotEmpty(jsonObject)) {
                    long chineseCount = jsonObject.values().stream()
                            .filter(ObjectUtils::isNotEmpty)
                            .map(String::valueOf)
                            .filter(s -> chinesePattern.matcher(s).matches())
                            .count();
                    if (chineseCount > 1) {
                        typeEnum = ChartTypeEnum.TABLE_CHART;
                    }
                }

            }

        } else if (typeEnum == ChartTypeEnum.LINE_CHART && columnData.size() > 2) {
            typeEnum = ChartTypeEnum.TABLE_CHART;
        }


        // 处理器分发（你也可以写成 switch）
        Object processedData;
        switch (typeEnum) {
            case PIE_CHART:
                processedData = DbQaDataProcess.processPieChart(llm_info, columnData, chart_data);
                break;
            case BAR_CHART:
                processedData = DbQaDataProcess.processBarChart(llm_info, columnData, chart_data);
                break;
            case LINE_CHART:
                processedData = DbQaDataProcess.processLineChart(llm_info, columnData, chart_data);
                break;
            case TABLE_CHART:
            default:
                processedData = DbQaDataProcess.processTableChart(llm_info, columnData, chart_data);
        }

        Map<String, Object> result = new HashMap<>();
        result.put("chart_type", typeEnum.getType());
        result.put("template_code", typeEnum.getTemplateCode());
        result.put("data", processedData);
        result.put("note", defaultResult.get("note"));

        return JSON.toJSONString(result);
    }

}
